from fastapi import FastAPI, HTTPException
from fastapi.exceptions import  RequestValidationError, ResponseValidationError
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
from starlette.middleware.cors import CORSMiddleware
from core import Events, Exception, Router
from core.Middleware import BaseMiddleware
from fastapi.openapi.utils import get_openapi

from core.Config import settings
from core.Lifespan import combined_lifespan

app = FastAPI(
    title=settings.PROJECT_NAME,
    description=settings.DESCRIPTION,
    version=settings.VERSION,
    # 默认不展开
    swagger_ui_parameters={
        "defaultModelsExpandDepth": -1,
        "docExpansion": "none",
        "persistAuthorization": True  # 确保授权信息在页面刷新或请求中保持
    },
    lifespan=combined_lifespan,
    swagger_ui_oauth2_redirect_url=settings.SWAGGER_UI_OAUTH2_REDIRECT_URL,
)

# 自定义多个认证信息
# def custom_openapi():
#     if app.openapi_schema:
#         return app.openapi_schema

#     openapi_schema = get_openapi(
#         title=settings.PROJECT_NAME,
#         description=settings.DESCRIPTION,
#         version=settings.VERSION,
#         routes=app.routes,
#     )

#     # # 移除默认的安全认证方案，假设默认的名称是 `OAuth2PasswordBearer`
#     # if "OAuth2PasswordBearer" in openapi_schema["components"]["securitySchemes"]:
#     #     del openapi_schema["components"]["securitySchemes"]["OAuth2PasswordBearer"]

#     # 定义后端 token 的安全方案
#     openapi_schema["components"]["securitySchemes"]["OAuth2Backend"] = {
#         "type": "oauth2",
#         "flows": {
#             "password": {
#                 "tokenUrl": "/admin/system/admin/getAccessToken",
#                 "scopes": {},
#             }
#         }
#     }

#     # 定义 API token 的安全方案
#     openapi_schema["components"]["securitySchemes"]["OAuth2API"] = {
#         "type": "oauth2",
#         "flows": {
#             "password": {
#                 "tokenUrl": "/api/user/getAccessToken",
#                 "scopes": {},
#             }
#         }
#     }

#     # 设置默认授权方式，可以在此处设置默认的安全方案
#     # openapi_schema["security"] = [{"OAuth2Backend": []}]  # 默认后端 OAuth2

#     # 为路径设置对应的安全方案
#     for path in openapi_schema["paths"]:
#         if "/backend-data" in path:
#             openapi_schema["paths"][path]["get"]["security"] = [{"OAuth2Backend": []}]
#         if "/api-data" in path:
#             openapi_schema["paths"][path]["get"]["security"] = [{"OAuth2API": []}]

#     app.openapi_schema = openapi_schema
#     return app.openapi_schema

# app.openapi = custom_openapi


# # @app.middleware("http")
# # async def read_body(request: Request, call_next):
# #     body = await request.body()
# #     # print(request.__dict__)
# #     print("请求体:", body)
# #     request._receive = asyncio.coroutine(lambda: BytesIO(request).read())
# #     response = await call_next(request)
# #     return response

# 生命周期
# app.add_event_handler("startup", Events.startup(app))
# app.add_event_handler("shutdown", Events.stopping(app))

# # 异常捕获
app.add_exception_handler(HTTPException, Exception.http_error_handler)
app.add_exception_handler(RequestValidationError, Exception.request_validationerror_handler)
app.add_exception_handler(ResponseValidationError, Exception.response_validationerror_handler)
# WebSocketException
# WebSocketRequestValidationError
# WebSocketDisconnect

# 中间件-跨域中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.CORS_ORIGINS,
    allow_credentials=settings.CORS_ALLOW_CREDENTIALS,
    allow_methods=settings.CORS_ALLOW_METHODS,  # 一个允许跨域请求的 HTTP 方法列表
    allow_headers=settings.CORS_ALLOW_HEADERS,  # 一个允许跨域请求的 HTTP 请求头列表
)

# 中间件-seesion
app.add_middleware(
    SessionMiddleware,
    secret_key=settings.SECRET_KEY,
    session_cookie=settings.SESSION_COOKIE,
    max_age=settings.SESSION_MAX_AGE
)

# 自定义中间件
# app.middleware("http")(Middleware.BaseMiddleware)
app.add_middleware(BaseMiddleware)


# 路由
app.include_router(Router.ALL_Router)

# 静态资源挂载
app.mount('/', StaticFiles(directory=settings.STATIC_DIR), name="static")



if __name__ == '__main__':
    import uvicorn
    uvicorn.run('main:app', host='0.0.0.0', port=7000, reload=True, workers=1)


